home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS01.ADF / C / freedraw.c < prev    next >
C/C++ Source or Header  |  1985-11-15  |  33KB  |  819 lines

  1. /************************************************************************/
  2. /***                FreeDraw - PD graphics for Amiga                  ***/
  3. /***                                                                  ***/
  4. /***      This is an extremely simple graphics editor which works in  ***/
  5. /***   the windowing environment of the Amiga.  It is very limited    ***/
  6. /***   in features, but I hope to add a lot more, and I would be      ***/
  7. /***   happy to receive assistance from anyone who wants to give it.  ***/
  8. /***      The basic idea of this program is to provide some minimal   ***/
  9. /***   image editing functions which can be used to develop images    ***/
  10. /***   for other programs.  I know there will be a lot of Paint type  ***/
  11. /***   type programs avaialable soon, but what are we supposed to use ***/
  12. /***   now?  The most important features to add now will probably be  ***/
  13. /***   those related to "cut and paste", disk srtorage and retrieval, ***/
  14. /***   and "single-pixel" editing like Mac's "fatbits".               ***/
  15. /***      I intend to use the IFF standard for the image storage and  ***/
  16. /***   retrieval and will be coding a "Files" menu soon.  The work    ***/
  17. /***   required for "cut and paste" should be almost trivial, but I   ***/
  18. /***   still may not get to it for a while.  Fatbits editing from one ***/
  19. /***   window to another involves some manipulations of the RastPorts ***/
  20. /***   which still elude me, as I have only recently begun to use the ***/
  21. /***   Amiga and don't yet understand some important details of these ***/
  22. /***   structures.  This would be a great item for one of the genius  ***/
  23. /***   members of the Amiga programming community to provide.         ***/
  24. /***      There are only two menu topics in this version, so using it ***/
  25. /***   is really quite easy.  Boxes are not allowed to be drawn in    ***/
  26. /***   areas outside of the window where border gadgets are located,  ***/
  27. /***   and the pen-draw mode also clips to these same boundaries.  If ***/
  28. /***   you have begun to draw a box by clicking the left button while ***/
  29. /***   the cursor is located in the FreeDraw window, then you can     ***/
  30. /***   cancel that box by clicking the right button.  In the pen mode ***/
  31. /***   pressing and holding the left button will draw.   Colors are   ***/
  32. /***   selected by simply releasing the menu button over the desired  ***/
  33. /***   color in the Color menu.   The erase feature always clears the ***/
  34. /***   window to the currently selected color.                        ***/
  35. /***      This is no gem of programming style, but you're getting it  ***/
  36. /***   for the right price so be patient with its design flaws.  New  ***/
  37. /***   versions will appear here on BIX as soon as I can get them in  ***/
  38. /***   shape for release.  I apologize to anyone who objects to my    ***/
  39. /***   lack of coding grace, but I just want to get the project off   ***/
  40. /***   the ground, and improvements will be forthcoming.  There are   ***/
  41. /***   a lot of comments, but I didn't know what needed to be made    ***/
  42. /***   clear so I just commented everything.                          ***/
  43. /***                                                                  ***/
  44. /***      If you like the idea of a PD graphics program and would be  ***/
  45. /***   interested in doing some development work, then please write   ***/
  46. /***   me at the address listed below, or call if you prefer.  I do   ***/
  47. /***   want to know if there is any interest in such a project, so    ***/
  48. /***   I will be glad to discuss any ideas you might have.  Also, as  ***/
  49. /***   I do not currently use CompuServe or any other major nets, I   ***/
  50. /***   would appreciate if someone would post this listing there.     ***/
  51. /***      I hope somebody enjoys this.  Have Fun.                     ***/
  52. /***                                           Rick Ross 11/14/85     ***/
  53. /***                                                                  ***/
  54. /***        My address:                                               ***/
  55. /***                    Richard M. Ross, Jr.                          ***/
  56. /***                    Eidetic Imaging                               ***/
  57. /***                    740 N. 22nd Street                            ***/
  58. /***                    Philadelphia, PA  19130                       ***/
  59. /***                                                                  ***/
  60. /***                    Phone - (215) 236-7388                        ***/
  61. /************************************************************************/
  62.  
  63. /*  compiler directives to fetch the necessary header files */
  64. #include <exec/types.h>
  65. #include <exec/exec.h>
  66. #include <intuition/intuition.h>
  67. #include <intuition/intuitionbase.h>
  68. #include <graphics/gfx.h>
  69. #include <graphics/regions.h>
  70. #include <graphics/copper.h>
  71. #include <graphics/gels.h>
  72. #include <graphics/gfxbase.h>
  73. #include <devices/keymap.h>
  74. #include <hardware/blit.h>
  75.  
  76. /*   These definitions are used by intuition for
  77.  *   calls to OpenLibrary() in order to ensure
  78.  *   that an appropriate ROM revision is
  79.  *   available.
  80.  */
  81. #define INTUITION_REV 1
  82. #define GRAPHICS_REV  1
  83.  
  84. /*   Intuition always wants to see these declarations */
  85. struct IntuitionBase *IntuitionBase;
  86. struct GfxBase *GfxBase;
  87.  
  88. /*   This is the Window structure declaration.
  89.  *   Nothing fancy is going on here, but note
  90.  *   the Flags and IDCMPFlags members of the
  91.  *   structure define which messages will be
  92.  *   sent by Intuition.  I haven't used them all
  93.  *   and if you want to change the settings you
  94.  *   should probably do it her instead of using
  95.  *   ModifyIDCMP later.
  96.  */
  97. struct NewWindow NewWindow = {
  98.    20,
  99.    20,
  100.    300,
  101.    150,
  102.    0,
  103.    1,
  104.    CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK
  105.    | NEWSIZE | INACTIVEWINDOW | SIZEVERIFY,
  106.    WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG
  107.    | WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE,
  108.    NULL,
  109.    NULL,
  110.    "AMIGA FreeDraw 0.01",
  111.    NULL,
  112.    NULL,
  113.    100, 35,
  114.    640, 200,
  115.    WBENCHSCREEN,
  116. };
  117.  
  118. /*******************************************************************/
  119. /*      DrawBox - Simple routine to draw an unfilled rectangle     */
  120. /*   It accepts the  coordinates of the top-left and lower-right   */
  121. /*   points of the rectangle, a pointer to the Window structure,   */
  122. /*   and the color in which to render the rectangle.  The current  */
  123. /*   FgPen color of the window is preserved thru the call.  No     */
  124. /*   clipping is done.                                             */
  125. /*******************************************************************/
  126. void DrawBox( tlx, tly, brx, bry, window, color )
  127. SHORT tlx, tly;                  /* top-left x,y coordinates */
  128. SHORT brx, bry;                  /* lower-right x,y coordinates */
  129. struct Window *window;           /* pointer to target window */
  130. BYTE color;                      /* color to use for render */
  131.    {
  132.    BYTE OldColor = window->RPort->FgPen;   /* save window's FgPen */
  133.  
  134.    SetAPen( window->RPort, color );        /* set draw color for box  */
  135.    Move(window->RPort, tlx, tly);          /* move to top-left point  */
  136.    Draw(window->RPort, brx, tly);          /* and draw to each of the */
  137.    Draw(window->RPort, brx, bry);          /* four corners of the box */
  138.    Draw(window->RPort, tlx, bry);
  139.    Draw(window->RPort, tlx, tly);
  140.    SetAPen( window->RPort, OldColor );     /* restore old FgPen */
  141.    }
  142.  
  143.  
  144. /*********************************************************/
  145. /*                 Color Select Menu                     */
  146. /*                                                       */
  147. /*      This is where the menu for color selection is    */
  148. /*   defined.  It should be flexible enough to allow for */
  149. /*   increased palette sizes, but this version is only   */
  150. /*   for the 4-color mode of the WorkBench screen.       */
  151. /*********************************************************/
  152.  
  153. /*   A few definitions are needed here.
  154.  *   Note that MAXPAL should be increased
  155.  *   to allow for palette larger than
  156.  *   four colors.    
  157.  */
  158. #define ITEMSTUFF (ITEMENABLED | HIGHBOX)
  159. #define CW 40
  160. #define CH 25
  161. #define MAXPAL 4
  162.  
  163. /*   declare enough storage for required
  164.  *   number of menu items and associated
  165.  *   images.  This menu will be using
  166.  *   graphics renditions of menu items,
  167.  *   so the Image structures must be
  168.  *   declared.  This menu is modeled after
  169.  *   the one found in the IconEd source.
  170.  */
  171. struct MenuItem coloritem[MAXPAL];
  172. struct Image colorimage[MAXPAL];
  173.  
  174. /*   array of palette sizes to correspond with
  175.  *   depth of window in bit-planes
  176.  */
  177. SHORT palette[] = { 2, 4, 8, 16, 32 };
  178.  
  179.  
  180. /*****************************************************************/
  181. /*    The following function initializes the structure arrays    */
  182. /*   needed to provide the Color menu topic.                     */
  183. /*****************************************************************/
  184. InitColorItems( depth )
  185. SHORT depth;               /* number of bit-planes in window */
  186.    {
  187.    SHORT n, colors;
  188.  
  189.    colors = palette[depth-1];
  190.    for( n=0; n<colors; n++ )           /* loop for max number of items */
  191.       {
  192.       coloritem[n].NextItem = &coloritem[n+1];
  193.       coloritem[n].ItemFill = (APTR)&colorimage[n];
  194.       /*   the next two items might be changed for
  195.        *   when bit-planes is greater than 2
  196.        */
  197.       coloritem[n].LeftEdge = 2 + CW * (n % 4);
  198.       coloritem[n].TopEdge = CH * (n / 4);
  199.       coloritem[n].Width = CW;
  200.       coloritem[n].Height = CH;
  201.       coloritem[n].Flags = ITEMSTUFF;
  202.       coloritem[n].MutualExclude = 0;
  203.       coloritem[n].SelectFill = NULL;
  204.       coloritem[n].Command = 0;
  205.       coloritem[n].SubItem = NULL;
  206.       coloritem[n].NextSelect = 0;
  207.  
  208.       colorimage[n].LeftEdge = 1;
  209.       colorimage[n].TopEdge = 1;
  210.       colorimage[n].Width = CW-2;
  211.       colorimage[n].Height = CH-2;
  212.       colorimage[n].Depth = depth;
  213.       colorimage[n].ImageData = NULL;
  214.       colorimage[n].PlanePick = 0;
  215.       colorimage[n].PlaneOnOff = n;
  216.       }
  217.    coloritem[colors-1].NextItem = NULL;   /* needed for last item in list */
  218.    return( 0 );
  219.    }
  220.  
  221.  
  222. /*****************************************************/
  223. /*                Draw Mode Menu                     */
  224. /*                                                   */
  225. /*      Here are the code and data declarations for  */
  226. /*   the DrawMode menu.  Current choices are limited */
  227. /*   to Erase, Filled Box, Hollow Box, and PenDraw.  */
  228. /*****************************************************/
  229.  
  230. /* define maximum number of menu items */
  231. #define DMODEMAX 4
  232.  
  233. /*   declare storage space for menu items and
  234.  *   their associated IntuiText structures
  235.  */
  236. struct MenuItem DModeItem[DMODEMAX];
  237. struct IntuiText DModeText[DMODEMAX];
  238.  
  239. /*****************************************************************/
  240. /*    The following function initializes the structure arrays    */
  241. /*   needed to provide the DrawMode menu topic.                  */
  242. /*****************************************************************/
  243. InitDModeItems()
  244.    {
  245.    short n;
  246.  
  247.    /* initialize each meu item and IntuiText with loop */
  248.    for( n=0; n<DMODEMAX; n++ )
  249.       {
  250.       DModeItem[n].NextItem = &DModeItem[n+1];
  251.       DModeItem[n].LeftEdge = 0;
  252.       DModeItem[n].TopEdge = 10 * n;
  253.       DModeItem[n].Width = 112;
  254.       DModeItem[n].Height = 10;
  255.       DModeItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
  256.       DModeItem[n].MutualExclude = 0;
  257.       DModeItem[n].ItemFill = (APTR)&DModeText[n];
  258.       DModeItem[n].SelectFill = NULL;
  259.       DModeItem[n].Command = 0;
  260.       DModeItem[n].SubItem = NULL;
  261.       DModeItem[n].NextSelect = 0;
  262.  
  263.       DModeText[n].FrontPen = 0;
  264.       DModeText[n].BackPen = 1;
  265.       DModeText[n].DrawMode = JAM2;     /* render in fore and background */
  266.       DModeText[n].LeftEdge = 0;
  267.       DModeText[n].TopEdge = 1;
  268.       DModeText[n].ITextFont = NULL;
  269.       DModeText[n].NextText = NULL;
  270.       }
  271.    DModeItem[DMODEMAX-1].NextItem = NULL;
  272.  
  273.    /* initialize text for specific menu items */
  274.    DModeText[0].IText = (UBYTE *)"Erase All";
  275.    DModeText[1].IText = (UBYTE *)"Hollow Box";
  276.    DModeText[2].IText = (UBYTE *)"Filled Box";
  277.    DModeText[3].IText = (UBYTE *)"Pen Draw";
  278.  
  279.    return( 0 );
  280.    }
  281.  
  282.  
  283. /***************************************************/
  284. /*                Menu Definition                  */
  285. /*                                                 */
  286. /*      This section of code is where the simple   */
  287. /*   menu definition goes.  For now it supports    */
  288. /*   only Color and Drawmode selection, but new    */
  289. /*   choices can easily be added by creating       */
  290. /*   structures and initializations functions      */
  291. /*   similar to those provided above.              */
  292. /***************************************************/
  293.  
  294. /* current number of available menu topics */
  295. #define MAXMENU 2
  296.  
  297. /*   declaration of menu structure array for
  298.  *   number of current topics.  Intuition
  299.  *   will use the address of this array to
  300.  *   set and clear the menus associated with
  301.  *   the window.
  302.  */
  303. struct Menu menu[MAXMENU];
  304.  
  305. /**********************************************************************/
  306. /*   The following function initializes the Menu structure array with */
  307. /*  appropriate values for our simple menu strip.  Review the manual  */
  308. /*  if you need to know what each value means.                        */
  309. /**********************************************************************/
  310. InitMenu()
  311.    {
  312.    menu[0].NextMenu = &menu[1];
  313.    menu[0].LeftEdge = 10;
  314.    menu[0].TopEdge = 0;
  315.    menu[0].Width = 50;
  316.    menu[0].Height = 10;
  317.    menu[0].Flags = MENUENABLED;
  318.    menu[0].MenuName = "Color";           /* text for menu-bar display */
  319.    menu[0].FirstItem = &coloritem[0];    /* pointer to first item in list */
  320.  
  321.    menu[1].NextMenu = NULL;
  322.    menu[1].LeftEdge = 65;
  323.    menu[1].TopEdge = 0;
  324.    menu[1].Width = 85;
  325.    menu[1].Height = 10;
  326.    menu[1].Flags = MENUENABLED;
  327.    menu[1].MenuName = "DrawMode";        /* text for menu-bar display */
  328.    menu[1].FirstItem = &DModeItem[0];    /* pointer to first item in list */
  329.  
  330.    return( 0 );
  331.    }
  332.  
  333.  
  334. /******************************************************/
  335. /*                   Main Program                     */
  336. /*                                                    */
  337. /*      This is the main body of the program.         */
  338. /******************************************************/
  339.  
  340. main()
  341.    {
  342.    struct Window *Window;              /* ptr to applications window */
  343.    struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
  344.    BYTE DrawColor = 1;                 /* initial drawing color */
  345.    SHORT OldBRX = 30, OldBRY = 30;     /* point coords used for boxes */
  346.    SHORT TLX = 20, TLY = 20;           /* initial top-left point coords */
  347.    ULONG class;                        /* used in message monitor loop */
  348.    USHORT code;                        /* used in message monitor loop */
  349.    SHORT x, y, x1, y1, x2, y2;         /* various coordinate variables */
  350.    SHORT MinX, MinY, MaxX, MaxY;       /* clipping boundary variables */
  351.    USHORT MenuNum, ItemNum;
  352.  
  353.    /*   The following is a set of declarations
  354.     *   for a number of flag values used by the
  355.     *   program.  These would perhaps be better
  356.     *   coded as a bit-field for all the flags,
  357.     *   but I'm lazy, and this is easier.
  358.     */
  359.    SHORT MouseMoved = FALSE;     /* indicates new mouse position ready */
  360.    SHORT KeepGoing = TRUE;       /* main loop control value */
  361.    SHORT ClipIt = FALSE;         /* are new point coords out of bounds? */
  362.    SHORT ClippedLast = FALSE;    /* was last PenDraw operation clipped? */
  363.    SHORT PenMode = FALSE;        /* indicates PenDraw mode is set */      
  364.    SHORT PenDown = FALSE;        /* if mouse moved, then should it draw? */
  365.    SHORT RubberBox = FALSE;      /* are we currently rubberbanding a box? */
  366.    SHORT FilledBox = FALSE;      /* should boxes be filled when drawn? */
  367.  
  368.    /* attempt to Open Library to access Intuition */
  369.    IntuitionBase = (struct IntuitionBase *)
  370.       OpenLibrary("intuition.library", INTUITION_REV);
  371.    if( IntuitionBase == NULL )
  372.       exit(FALSE);
  373.  
  374.    /* attempt to OpenLibrary to access Graphics functions */
  375.    GfxBase = (struct GfxBase *)
  376.       OpenLibrary("graphics.library",GRAPHICS_REV);
  377.    if( GfxBase == NULL )
  378.       exit(FALSE);
  379.  
  380.  
  381.    /* Try to open new window for application */
  382.    if(( Window = (struct Window *)OpenWindow(&NewWindow) ) == NULL)
  383.       exit(FALSE);
  384.  
  385.    /*   set initial clipping boundaries
  386.     *   from the values found in the window
  387.     *   structure for border dimensions
  388.     */
  389.    MinX = Window->BorderLeft;
  390.    MinY = Window->BorderTop;
  391.    MaxX = Window->Width - Window->BorderRight - 1;
  392.    MaxY = Window->Height - Window->BorderBottom - 1;
  393.  
  394.    InitColorItems( 2 );         /* initialize Color menu arrays */
  395.    InitDModeItems();            /* initialize DrawMode menu arrays */
  396.    InitMenu();                  /* initialize the menu structures */
  397.  
  398.    /*   Now, having initialized the various arrays
  399.     *   of structures required for menu generation
  400.     *   we can tell Intuition to make our menus
  401.     *   available to the user when this window
  402.     *   is active.
  403.     */
  404.    SetMenuStrip( Window, &menu[0] );
  405.  
  406.    /* set initial drw mode and color */
  407.    SetDrMd( Window->RPort, JAM1 );
  408.    SetAPen( Window->RPort, DrawColor );
  409.  
  410.    /*   Everything the program needs is now
  411.     *   initialized and put in place.  The
  412.     *   program enters the following loop
  413.     *   and processes message continuously as
  414.     *   they are received from Intuition.
  415.     *      I guess this loop is the real workhorse
  416.     *   of the program.  By the way, the loop
  417.     *   control variable KeepGoing remains TRUE
  418.     *   until a CLOSEWINDOW message is received.
  419.     *   At that point it goes FALSE, and the
  420.     *   program cleans up and exits.
  421.     */
  422.    while( KeepGoing )
  423.       {
  424.  
  425.       /* stay here until a message is received from Intuition */
  426.       Wait( 1 << Window->UserPort->mp_SigBit);
  427.  
  428.       MouseMoved = FALSE;    /* clear this flag each time thru loop */
  429.  
  430.       /*   since more than one message may be waiting
  431.        *   a reply at this point, a loop is used to
  432.        *   process all that have come in until no more
  433.        *   are ready.  Msg received is assigned to
  434.        *   NewMessage from the GetMsg() function.  This
  435.        *   value will be NULL if no message is ready,
  436.        *   and control passes out of the loop at that time
  437.        */
  438.       while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
  439.          {
  440.  
  441.          /*   copy some values from the message structure
  442.           *   to variables used in the switch statements
  443.           *   below
  444.           */
  445.          class = NewMessage->Class;
  446.          code = NewMessage->Code;
  447.          x = Window->MouseX;
  448.          y = Window->MouseY;
  449.  
  450.          /*   SIZEVERIFY is a very high priority message
  451.           *   in our loop and requires some immediate
  452.           *   servicing.  Any outstanding draw operations
  453.           *   are immediately cancelled, and the DrawMode
  454.           *   is nulled.  This prevents any attempts to
  455.           *   render outside whatever new Window boundaries
  456.           *   the user chooses.
  457.           */
  458.          if( class == SIZEVERIFY )
  459.             {
  460.             PenDown = FALSE;
  461.             if( RubberBox )
  462.                {
  463.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  464.                Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  465.                RubberBox = FALSE;
  466.                }
  467.             }
  468.  
  469.          /*   we have all the information needed from
  470.           *   the message, so we can now safely reply
  471.           *   to it without losing data
  472.           */
  473.          ReplyMsg( NewMessage );
  474.  
  475.          /*  Examine point coords from message received
  476.           *  and set the clipping flag if out of bounds.
  477.           *  If user was drawing in PenMode when message
  478.           *  was received, then the ClippedLast flag
  479.           *  should also be set to indicate this to the
  480.           *  next draw operation.
  481.           */
  482.          if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY ))
  483.             if( PenDown )
  484.                ClippedLast = TRUE;
  485.  
  486.  
  487.          /* enter switch on type of message received */
  488.          switch( class )
  489.          {
  490.             case MOUSEMOVE:
  491.                /*   Don't really do anything with this one
  492.                 *   until any other, more important, messages
  493.                 *   are received and processed.
  494.                 */
  495.                MouseMoved = TRUE;
  496.                break;
  497.  
  498.             case NEWSIZE:
  499.                /*  set new clipping boundaries */
  500.                MinX = Window->BorderLeft;
  501.                MinY = Window->BorderTop;
  502.                MaxX = Window->Width - Window->BorderRight - 1;
  503.                MaxY = Window->Height - Window->BorderBottom - 1;
  504.                break;
  505.  
  506.             case CLOSEWINDOW:
  507.                /*   User is ready to quit, so indicate
  508.                 *   that execution should terminate
  509.                 *   with next iteration of the loop.
  510.                 */
  511.                KeepGoing = FALSE;
  512.                break;
  513.  
  514.             case MOUSEBUTTONS:
  515.                /*   A number of things could have happened
  516.                 *   here, and further examination of data
  517.                 *   received from message is needed to
  518.                 *   determine what action should be taken.
  519.                 *   The code variable holds important info
  520.                 *   about what actually caused the message
  521.                 *   to be sent in the first place.
  522.                 */
  523.                switch ( code )
  524.                   {
  525.                   case SELECTUP:
  526.                      /*   User was holding down the left button
  527.                       *   and just released it.  The PenMode
  528.                       *   flag variables are set accordingly.
  529.                       *   The pen can no longer be down, and
  530.                       *   ClippedLast is reset for next time.
  531.                       */
  532.                      PenDown = ClippedLast = FALSE;
  533.                      break;
  534.  
  535.                   case SELECTDOWN:
  536.                      /*   User has pressed the left button, and
  537.                       *   several differnt actions may need to
  538.                       *   be taken.  If the ClipIt value is TRUE,
  539.                       *   then no action should be taken at all.
  540.                       */
  541.                      if( ClipIt )
  542.                         break;
  543.  
  544.                      /*   If user is currently in PenMode, then
  545.                       *   set up to draw when MOUSEMOVED messages
  546.                       *   are received until a subsequent SELECTUP
  547.                       *   message comes in.
  548.                       */
  549.                      if( PenMode )
  550.                         {
  551.                         PenDown = TRUE;
  552.                         ClippedLast = FALSE;
  553.  
  554.                         /* make sure to set appropriate mode */
  555.                         SetDrMd( Window->RPort, JAM1 );
  556.  
  557.                         /* and establish initial position to draw */
  558.                         Move( Window->RPort, x, y );
  559.                         break;
  560.                         }
  561.  
  562.                      /*   If user is currently rubberbanding a box,
  563.                       *   then a SELECTDOWN message means it is time
  564.                       *   to stop rubberbanding and actually draw it.
  565.                       *   The following code will be executed if
  566.                       *   this is the case, and it will determine if
  567.                       *   a filled box is needed before rendering.
  568.                       */
  569.                      if( RubberBox )
  570.                         {
  571.                         /*   set draw mode back to JAM1 since
  572.                          *   it is now currently set to COMPLEMENT
  573.                          */
  574.                         SetDrMd( Window->RPort, JAM1 );
  575.                         RubberBox = FALSE;   /* turn off rubberbanding */
  576.  
  577.                         /*   Restore the condition of the RMBTRAP
  578.                          *   bit in the Window structure's Flags
  579.                          *   member.  Menubutton events will no
  580.                          *   be received by this loop.
  581.                          */
  582.                         Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  583.  
  584.                         /*   RectFill is not condusive to the smooth
  585.                          *   execution of programs iit arguments are
  586.                          *   out of order, sot his code sorts them
  587.                          *   in preparation for the call.
  588.                          */
  589.                         if( FilledBox )
  590.                            {
  591.                            /* first sort the x-coords */
  592.                            if( TLX < OldBRX )  {
  593.                               x1 = TLX;  x2 = OldBRX;  }
  594.                            else  {
  595.                               x1 = OldBRX;  x2 = TLX;  }
  596.  
  597.                            /* then sort the y-coords */
  598.                            if( TLY < OldBRY )  {
  599.                               y1 = TLY;  y2 = OldBRY;  }
  600.                            else  {
  601.                               y1 = OldBRY;  y2 = TLY;  }
  602.  
  603.                            /* now generate the filled rectangle */
  604.                            RectFill( Window->RPort, x1, y1, x2, y2 );
  605.                            }
  606.                         else
  607.                            {
  608.                            /* FilledBox not set, so draw hollow box */
  609.                            DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  610.                            }
  611.                         break;
  612.                         }
  613.  
  614.                      /*   If execution comes here, then PenMode was
  615.                       *   not set and user was not rubberbanding.
  616.                       *   SELECTDOWN therefore indicates to start the
  617.                       *   rubberbanding process at this point.  The
  618.                       *   initial coords are set to the values we
  619.                       *   received when the GetMsg() was executed.
  620.                       */
  621.                      TLX = OldBRX = x;  TLY = OldBRY = y;
  622.  
  623.                      /* set to render in XOR mode */
  624.                      SetDrMd( Window->RPort, COMPLEMENT );
  625.  
  626.                      /* set flag to indicate we are now rubberbanding */
  627.                      RubberBox = TRUE;
  628.  
  629.                      /*   This instruction indicates to Intuition
  630.                       *   that we now wish to receive a message
  631.                       *   each time the Menubutton is pressed.
  632.                       *   This is how we hijack the right button
  633.                       *   for temporary use as a Cancel button
  634.                       *   instead of a Menubutton.
  635.                       */
  636.                      Window->Flags |= RMBTRAP;
  637.  
  638.                      /* render the initial rubberbox and exit */
  639.                      DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  640.                      break;
  641.  
  642.                   case MENUDOWN:
  643.                      /*   WE only receive this message class if
  644.                       *   the RMBTRAP flag bit has been set, so
  645.                       *   it always means that we should cancel
  646.                       *   the box which is currently rubberbanding.
  647.                       */
  648.                      /* turn the flag off */
  649.                      RubberBox = FALSE;
  650.  
  651.                      /* restore control of menubutton to Intuition */
  652.                      Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  653.  
  654.                      /*   erase (by double XOR'ing) the current
  655.                       *   rubberbox and exit switch.
  656.                       */
  657.                      DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  658.                      break;
  659.  
  660.                   default:
  661.                      /*   Something unimportant happened, so just
  662.                       *   continue thru the GetMsg() loop.
  663.                       */
  664.                      continue;
  665.                }
  666.                break;
  667.  
  668.             case MENUPICK:
  669.                /*   A menu event has taken place and is
  670.                 *   ready to be processed.  Examine the
  671.                 *   code variable received from the message
  672.                 *   to determine what action should be taken.
  673.                 *   The first check is for MENUNULL, which
  674.                 *   means that nothing should be done at all.
  675.                 */
  676.                if( code != MENUNULL )
  677.                   {
  678.                   /* get menu and item numbers from code */
  679.                   MenuNum = MENUNUM( code );
  680.                   ItemNum = ITEMNUM( code );
  681.  
  682.                   /* determine appropriate action by menu number */
  683.                   switch ( MenuNum )
  684.                      {
  685.                      case 0:
  686.                         /*   Menu 0 is the Color menu.  The
  687.                          *   item number indicates which new
  688.                          *   color to set.
  689.                          */
  690.                         DrawColor = ItemNum;
  691.                         SetAPen( Window->RPort, DrawColor );
  692.                         break;
  693.  
  694.                      case 1:
  695.                         /*   Menu 1 is the DrawMode menu.  The item
  696.                          *   number indicates what to do.
  697.                          *   NOTE:  Since we cannot have received
  698.                          *   this message if we were rubberbanding,
  699.                          *   then there is no need to clean up before
  700.                          *   changing drawing modes.
  701.                          */
  702.                         switch ( ItemNum )
  703.                            {
  704.                            case 0:
  705.                               /* Erase window to current color */
  706.                               SetDrMd( Window->RPort, JAM1 );
  707.                               RectFill( Window->RPort, MinX,MinY,MaxX,MaxY);
  708.                               break;
  709.  
  710.                            case 1:
  711.                               /* set flag variables for hollow box */
  712.                               PenMode = FALSE;
  713.                               FilledBox = FALSE;
  714.                               break;
  715.  
  716.                            case 2:
  717.                               /* set flag variables for filled box */
  718.                               PenMode = FALSE;
  719.                               FilledBox = TRUE;
  720.                               break;
  721.  
  722.                            case 3:
  723.                               /* set flag variables for PenMode */
  724.                               PenMode = TRUE;
  725.                               break;
  726.  
  727.                            default:
  728.                               /* don't do anything */
  729.                               break;
  730.                            }
  731.                         break;
  732.  
  733.                      default:
  734.                         /* Menu number unrecognized, do nothing */
  735.                         break;
  736.                      }
  737.                   }
  738.                break;
  739.  
  740.             case INACTIVEWINDOW:
  741.                /*   User has de-selected our window, so a
  742.                 *   little bit of cleaning up may be needed
  743.                 *   to prevent untoward events when he comes
  744.                 *   back to it.
  745.                 */
  746.                /* erase any outstanding rubberbox */
  747.                if( RubberBox )
  748.                   DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  749.  
  750.                /* reset all the flafg variables */
  751.                PenDown = ClippedLast = RubberBox = FALSE;
  752.  
  753.                /* return possibly diverted menubutton events to Big I */
  754.                Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  755.                break;
  756.  
  757.             default:
  758.                /* message class was unrecognized, so do nothing */
  759.                break;
  760.             }
  761.          }   /* this brace ends the while(NewMessage) loop way back when */
  762.  
  763.       /*   There are no more messages waiting at the
  764.        *   IDCMP port, so we can now proceed to
  765.        *   process any MOUSEMOVED message we may
  766.        *   have received.
  767.        */
  768.       if( MouseMoved && !ClipIt)
  769.          {
  770.          /* the mouse did move, and we don't need to clip */
  771.  
  772.          /* check first if we are drawing in PenMode */
  773.          if( PenDown )
  774.             {
  775.             /*   We have to examine if we clipped the
  776.              *   last PenMode draw operation.  If we did,
  777.              *   then this is the first move back into
  778.              *   window boundaries, so we mov instead of
  779.              *   drawing.
  780.              */
  781.             if( ClippedLast )
  782.                {
  783.                ClippedLast = FALSE;         /* reset this flag now */
  784.                Move( Window->RPort, x, y );
  785.                }
  786.             else
  787.                Draw( Window->RPort, x, y ); /* draw to x,y coords */
  788.          }
  789.          else
  790.             {
  791.             /*   We weren't in PenMode, but we still might
  792.              *   be rubberbanding a box.  If so, then we
  793.              *   should erase the current rubberbox and
  794.              *   draw a new one with the new mouse coords.
  795.              */
  796.             if( RubberBox )
  797.                {
  798.                /* erase the old rubberbox - draw mode is COMPLEMENT */
  799.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  800.  
  801.                /* assign new values to box coords */
  802.                OldBRX = x;  OldBRY = y;
  803.  
  804.                /* and draw the new rubberbox */ 
  805.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  806.                }
  807.             }
  808.          }
  809.       }
  810.  
  811.    /*   It must be time to quit, so we have to clean
  812.     *   up and exit.
  813.     */
  814.    ClearMenuStrip( Window );
  815.    CloseWindow( Window );
  816.    exit(TRUE);
  817.    }
  818.  
  819.